package com.tplhk.aviator;

import cn.hutool.json.JSONUtil;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.ILoadExpressCustomize;
import com.googlecode.aviator.Options;
import com.tplhk.aviator.function.collection.Exsit;
import com.tplhk.aviator.function.collection.NotExsit;
import com.tplhk.aviator.function.general.Age;
import com.tplhk.aviator.function.general.ChineseNumberUpper;
import com.tplhk.aviator.function.general.DiffDays;
import com.tplhk.aviator.function.general.StringNumbersSum;
import com.tplhk.aviator.function.number.*;
import com.tplhk.aviator.function.object.Nvl;
import com.tplhk.aviator.function.object.ToNumber;
import com.tplhk.aviator.function.object.ToString;
import com.tplhk.aviator.function.object.ToUpperCase;
import lombok.extern.slf4j.Slf4j;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.math.MathContext;


/**
 * @description: Aviator引擎执行器
 * @Date : 2021/8/31
 * @Author : xujunqiang
 */
@Slf4j
public final class AviatorExecutor {

    public AviatorExecutor(ILoadExpressCustomize loadExpressCustomize) {
        log.info("init AviatorEvaluator......");
        if (null != loadExpressCustomize) {
            AviatorEvaluator.getInstance().setLoadExpressCustomize(loadExpressCustomize);
        }

        AviatorEvaluator.setOption(Options.ALWAYS_PARSE_FLOATING_POINT_NUMBER_INTO_DECIMAL, true);
        AviatorEvaluator.setOption(Options.MATH_CONTEXT, MathContext.DECIMAL128);
        AviatorEvaluator.getInstance().setCachedExpressionByDefault(true);
        AviatorEvaluator.setFunctionMissing(new FunctionMissingCustomize());
        AviatorEvaluator.addFunction(new Nvl());
        AviatorEvaluator.addFunction(new Sum());
        AviatorEvaluator.addFunction(new Min());
        AviatorEvaluator.addFunction(new Max());
        AviatorEvaluator.addFunction(new Round());
        AviatorEvaluator.addFunction(new Ceil());
        AviatorEvaluator.addFunction(new Floor());
        AviatorEvaluator.addFunction(new Scale());
        AviatorEvaluator.addFunction(new Exsit());
        AviatorEvaluator.addFunction(new NotExsit());
        AviatorEvaluator.addFunction(new DiffDays());
        AviatorEvaluator.addFunction(new Age());
        AviatorEvaluator.addFunction(new ChineseNumberUpper());
        AviatorEvaluator.addFunction(new StringNumbersSum());
        AviatorEvaluator.addFunction(new ToNumber());
        AviatorEvaluator.addFunction(new ToString());
        AviatorEvaluator.addFunction(new ToUpperCase());

    }

    /**
     * 执行结果
     *
     * @param context 上下文对象
     * @return
     */
    public Object execute(AviatorContext context) {
        Object result = AviatorEvaluator.execute(context.getExpression(), context.getEnv(), context.isCached());
        log.info("Aviator执行器context={},result={}", JSONUtil.parseObj(context), result);
        return result;
    }

    public Object executeCache(AviatorContext context) {
        Object result = AviatorEvaluator.execute(context.getExpression(), context.getEnv(), AviatorEvaluator.getInstance().isCachedExpressionByDefault());
        log.info("Aviator执行器context={},result={}", JSONUtil.parseObj(context), result);
        return result;
    }

    public void setTraceFlag(Boolean traceFlag) {
        if (traceFlag) {
            AviatorEvaluator.setOption(Options.TRACE_EVAL, traceFlag);

            try {
                AviatorEvaluator.setTraceOutputStream(new FileOutputStream("aviator.log"));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}
